#!/bin/bash
# get_partition_uuid.sh
#
# 用途: 获取指定文件或目录所在分区的 UUID。
#
# 本脚本提供多种方法来获取目标分区的 UUID：
#   1. 使用 df 和 blkid
#   2. 使用 stat 和 mount 命令
#   3. 使用 lsblk 和 blkid
#   4. 使用 findmnt 和 blkid
#   5. 使用 /dev/disk/by-uuid 与 readlink
#   6. 使用 udevadm info 获取设备属性
#
# 用法: ./get_partition_uuid.sh [文件或目录]
# 如果不传参数，则默认使用当前目录 ($PWD)
#
# 示例:
#   ./get_partition_uuid.sh /path/to/your/dir_or_file
#
# 如需帮助，请运行: ./get_partition_uuid.sh --help

# 显示帮助信息
show_help() {
  cat <<EOF
Usage: $(basename "$0") [OPTIONS] [FILE_OR_DIR]

获取指定文件或目录所在分区的 UUID。

OPTIONS:
  -h, --help    显示本帮助信息并退出

FILE_OR_DIR:
  指定一个文件或目录，用于确定其所在分区。若不提供，则默认使用当前目录 ($PWD)。

本脚本提供以下6种方法：
  1. 使用 df 和 blkid
  2. 使用 stat 和 mount 命令
  3. 使用 lsblk 和 blkid
  4. 使用 findmnt 和 blkid
  5. 使用 /dev/disk/by-uuid 与 readlink
  6. 使用 udevadm info

EOF
}

# 检查是否请求帮助
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
  show_help
  exit 0
fi

# 检查是否需要 sudo 权限
if [[ $EUID -ne 0 ]]; then
  SUDO='sudo'
else
  SUDO=''
fi

# 通用函数：通过 df 获取目标所在的设备
get_device() {
  local file_or_dir="$1"
  df --output=source "$file_or_dir" | tail -n 1
}

# 方法一：使用 df 和 blkid
get_uuid_with_df_and_blkid() {
  local file_or_dir="$1"
  local device
  device=$(get_device "$file_or_dir")
  local uuid
  uuid=$($SUDO blkid -s UUID -o value "$device" 2>/dev/null)
  echo "$uuid"
}

# 方法二：使用 stat 和 mount 命令
get_uuid_with_stat_and_mount() {
  local file_or_dir="$1"
  local mount_point device
  mount_point=$(stat -c %m "$file_or_dir")
  device=$(mount | awk -v mp="$mount_point" '$3==mp {print $1}' | head -n 1)
  local uuid
  uuid=$($SUDO blkid -s UUID -o value "$device" 2>/dev/null)
  echo "$uuid"
}

# 方法三：使用 lsblk 和 blkid
get_uuid_with_lsblk_and_blkid() {
  local file_or_dir="$1"
  local mount_point device
  mount_point=$(df --output=target "$file_or_dir" | tail -n 1)
  device=$(lsblk -o NAME,MOUNTPOINT -nr | awk -v mp="$mount_point" '$2==mp {print "/dev/" $1}')
  local uuid
  uuid=$($SUDO blkid -s UUID -o value "$device" 2>/dev/null)
  echo "$uuid"
}

# 方法四：使用 findmnt 和 blkid
get_uuid_with_findmnt_and_blkid() {
  local file_or_dir="$1"
  local device
  device=$(findmnt --noheadings --output SOURCE --target "$file_or_dir")
  local uuid
  uuid=$($SUDO blkid -s UUID -o value "$device" 2>/dev/null)
  echo "$uuid"
}

# 方法五：使用 /dev/disk/by-uuid 与 readlink
get_uuid_with_by_uuid() {
  local file_or_dir="$1"
  local device
  device=$(get_device "$file_or_dir")
  for symlink in /dev/disk/by-uuid/*; do
    local target
    target=$(readlink -f "$symlink")
    if [[ "$target" == "$device" ]]; then
      echo "$(basename "$symlink")"
      return
    fi
  done
  echo ""
}

# 方法六：使用 udevadm info 获取设备属性
get_uuid_with_udevadm() {
  local file_or_dir="$1"
  local device
  device=$(get_device "$file_or_dir")
  local uuid
  uuid=$(udevadm info --query=property --name="$device" 2>/dev/null | grep '^ID_FS_UUID=' | cut -d'=' -f2)
  echo "$uuid"
}

# 主函数：依次调用各方法并输出结果
main() {
  local target="${1:-$PWD}"
  echo "目标文件/目录: $target"
  echo "----------------------------------------"
  echo "方法 1: 使用 df 和 blkid"
  echo "UUID: $(get_uuid_with_df_and_blkid "$target")"
  echo "----------------------------------------"
  echo "方法 2: 使用 stat 和 mount"
  echo "UUID: $(get_uuid_with_stat_and_mount "$target")"
  echo "----------------------------------------"
  echo "方法 3: 使用 lsblk 和 blkid"
  echo "UUID: $(get_uuid_with_lsblk_and_blkid "$target")"
  echo "----------------------------------------"
  echo "方法 4: 使用 findmnt 和 blkid"
  echo "UUID: $(get_uuid_with_findmnt_and_blkid "$target")"
  echo "----------------------------------------"
  echo "方法 5: 使用 /dev/disk/by-uuid 与 readlink"
  echo "UUID: $(get_uuid_with_by_uuid "$target")"
  echo "----------------------------------------"
  echo "方法 6: 使用 udevadm info"
  echo "UUID: $(get_uuid_with_udevadm "$target")"
}

main "$@"

